stage2: rework /data persistence (XTS, meta_bg) + mkruntime tooling#1
Merged
Conversation
/data: replace the planned authenticated dm-integrity + dm-crypt AEAD stack with
confidentiality-only dm-crypt aes-xts-plain64 (AES-256-XTS). Authenticated
encryption has no internal hash, so a never-written sector EIOs on read; ext4
online-resize does read-modify-write of new-group metadata (backup GDT via
ext4_setup_new_descs) in the region it grows into, so the resize aborts unless
the whole grow region is pre-wiped first -- O(volume), unacceptable on large
volumes. XTS decrypts unwritten sectors to garbage instead of erroring, so the
resize needs no wipe (the standard LUKS/dm-crypt pattern) and cold-boot cost is
independent of volume size. Trade: at-rest tampering garbles plaintext rather
than being cryptographically detected -- media integrity is left to the storage
layer (EBS et al.), and a raw-disk-write adversary is out of scope. Key drift
still fails closed (superblock decrypts to garbage -> no ext4 magic -> reinit).
64-byte TPM-derived key, new key label.
loader: as PID 1, own fatal boot errors instead of returning. A returning init
panics the kernel ("Attempted to kill init") and spins a vCPU at 100% forever
(in prod and the QEMU harness). Now: log, 60s grace for console capture, then a
clean ACPI power-off.
ext4 /data base: meta_bg (drop resize_inode) for unbounded online growth; no
resize= ceiling or journal bump needed. Verified growing to ~12 GiB across a
meta_bg boundary with no wipe.
mkruntime.sh: env knobs (SOURCE_DATE_EPOCH, DATA_SIZE_MB, ROOTFS_UUID,
VERITY_SALT) with reproducible defaults; rootfs input now accepts a tar stream
on stdin, a tar file, a directory, or a single binary (docker export documented
as an example, not a dependency); <out> is a file path or - for stdout; and
--bootstrap prepends the loader ELF to emit a ready-to-run packed stage2. The
Makefile pack target uses --bootstrap and forwards the knobs.
tests: pivot-init drops the tamper-detection check (property removed with the
AEAD stack); add grow-probe (large-volume meta_bg growth + sparse-hole). Prune
unused probe examples. make ci green; PIVOT_TEST=PASS and GROW_TEST=PASS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…E restructure Make lockboot:erofs-builder a one-shot CLI: bake tools/mkruntime.sh in as the ENTRYPOINT, so packaging no longer needs a repo bind-mount -- mount just the loader ELF, pipe a rootfs in on stdin, get the stage2 out on stdout. Drop coreutils (busybox covers touch -d @epoch, stat -c, tar, install, awk); output stays byte-identical (same root hash), image 20.3 -> 18.2 MB. Makefile pack passes args straight to the entrypoint. Restructure the README to lead with what it is and how to use it (the mkruntime one-liner with the built bootstrap), and move how-it-boots / security model / testing into a Technical details section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
HarryR
added a commit
to lockboot/stage0
that referenced
this pull request
Jul 13, 2026
## What Bring the stage0 build image and disk layout in line with the Fedora 44 chain bump, plus stable disk identity. ## Changes - **rpm + gnupg** added to `Dockerfile.build` so the UKI build can verify Fedora package GPG signatures (image parity with stage1, kept byte-identical). No effect on compiled artifacts. - **Stable lockboot GPT GUIDs + FAT volume-id.** `DISK_GUID` / `PART_GUID` are now constant across releases (`4c4f434b-424f-4f54-...`, "LOCKBOOT" + a role index), so the initial GPT is byte-stable (stable pre-stage2 PCR5) and the boot disk is identifiable by a fixed GUID rather than by hashing stage0.efi (which changed per release). This is the stable identity stage2's `find_boot_device` can key on. (stage2 still rewrites the GPT at runtime to add p2/p3, which is why it excludes PCR5 from its key binding.) - **Pin `vaportpm-attest` to v0.3.0** (rev + version guard), matching stage1. - **Extract the shared `DOCKER_RUN` harness** into `build.mk` (same refactor as stage1). ## Verification - Reproducible: GUIDs/timestamps fixed; build output byte-stable. - No change to the runtime boot path. Pairs with lockboot/stage1#19 (Fedora 44 kernel/stub) and lockboot/stage2#1. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Clean check-context names (no spaces/parens) so the uniform branch ruleset across the lockboot repos can require the same names everywhere. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks stage2
/datapersistence and the payload-forging tooling. Net change frommain:/data: dm-cryptaes-xts-plain64(AES-256-XTS) instead of the planned authenticated dm-integrity + AEAD. Authenticated encryption (no internal hash) makes a never-written sector EIO on read, and ext4 online-resize does read-modify-write of new-group metadata in the region it grows into, so the resize aborts unless the whole grow region is pre-wiped (O(volume), unviable on large volumes). XTS decrypts unwritten sectors to garbage, so resize needs no wipe. Trade: at-rest tamper garbles rather than being detected; media integrity is left to the storage layer, raw-disk adversary out of scope. Key drift still fails closed.resize=cap / journal bump).<out>as a file or-for stdout, and--bootstrapto emit a ready-to-run packed stage2. Makefile pack uses it.Verification
make cigreen (fmt + clippy-D warnings+ tests)PIVOT_TEST=PASS(config passthrough, attest chain, resize, persist-across-reboot, ephemeral overlay)GROW_TEST=PASS-- grew/datato ~12 GiB across a meta_bg boundary, no wipe, sparse hole reads zeroReview notes / open threads
meta_bggives unbounded growth;resize_inode+ aresize=cap is the bounded alternative if a hard ceiling is ever wanted.Draft for review.
🤖 Generated with Claude Code